package com.caigou.security.filter;


import com.alibaba.fastjson.JSONObject;
import com.caigou.security.exception.TokenIsExpiredException;
import com.caigou.security.utils.JwtTokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * Created by echisan on 2018/6/23
 */
@Slf4j
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {


    public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {

        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
        String permutation = null;
        if (ctx != null) {
            StringRedisTemplate stringRedisTemplate = ctx.getBean(StringRedisTemplate.class);
            String tokenHeader = request.getHeader(JwtTokenUtils.TOKEN_HEADER);
            if (!StringUtils.isEmpty(tokenHeader)) {
                permutation = stringRedisTemplate.opsForValue().get(tokenHeader);
                //当用户调用退出接口时删除用户redis中的token
                if (request.getRequestURL().toString().endsWith("/signOut")) {
                    //清除redis中的token
                    stringRedisTemplate.delete(tokenHeader);
                }
            }
        }
        if (permutation == null || !permutation.startsWith(JwtTokenUtils.TOKEN_PREFIX) || isPassPath(request)) {
            chain.doFilter(request, response);
            return;
        }
        try {
            Objects.requireNonNull(getAuthentication(permutation)).setDetails(new WebAuthenticationDetails(request));
            SecurityContextHolder.getContext().setAuthentication(getAuthentication(permutation));
        } catch (TokenIsExpiredException e) {
            //返回json形式的错误信息
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            //response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            //String reason = "统一处理，原因：" + e.getMessage();
            //response.getWriter().write(new ObjectMapper().writeValueAsString(reason));
            PrintWriter writer = response.getWriter();
            JSONObject object = new JSONObject();
            object.put("status", 401);
            object.put("message", e.getMessage());
            object.put("data", "");
            writer.write(object.toString());
            return;
        }
        super.doFilterInternal(request, response, chain);
    }

    private boolean isPassPath(HttpServletRequest request) {
        //String prefix = JwtTokenUtils.PREFIX;
        //String[] split = prefix.split(",");
        //List<String> prefixs = new ArrayList<>(Arrays.asList(split));
//        for (String pre : prefixs) {
//            if (request.getRequestURI().startsWith(pre)) {
//                return true;
//            }
//        }
        return false;
    }

    // 这里从token中获取用户信息并新建一个token
    private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) throws TokenIsExpiredException {


        String token = tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX, "");
        boolean expiration = JwtTokenUtils.isExpiration(token);
        if (expiration) {
            throw new TokenIsExpiredException("登录信息已过期,请重新登录");
        } else {
            String username = JwtTokenUtils.getUsername(token);
            List<String> authorities = JwtTokenUtils.getUserAuthorities(token);
            String userId = JwtTokenUtils.getUserId(token);
            if (username != null) {
                ArrayList<GrantedAuthority> auth = new ArrayList<>();
                if (!CollectionUtils.isEmpty(authorities)) {
                    authorities.forEach(privilege -> {
                        auth.add(new SimpleGrantedAuthority(privilege));
                    });
                }
                return new UsernamePasswordAuthenticationToken(username, userId, auth);
            }
        }
        return null;
    }

}
